﻿#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkSmartPointer.h>
#include <vtkCamera.h>
#include <vtkRendererCollection.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkClipPolyData.h>
#include <vtkClipClosedSurface.h>
#include <vtkProperty.h>
#include <vtkPlane.h>
#include <vtkPlaneCollection.h>
#include <vtkPointPicker.h>
#include <vtkWorldPointPicker.h>

/**
 * 使用vtkClipClosedSurface 截切，并生成表面
 */
//static vtkSmartPointer<vtkCellPicker> picker1;
static vtkSmartPointer<vtkRenderer> sRender;
/**************************************************************************************************/
class PointPickerInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
    static PointPickerInteractorStyle* New();
    vtkTypeMacro(PointPickerInteractorStyle, vtkInteractorStyleTrackballCamera);

    virtual void OnLeftButtonDown()
    {
        //打印鼠标左键像素位置
        std::cout << "Picking pixel: " << this->Interactor->GetEventPosition()[0]
            << " " << this->Interactor->GetEventPosition()[1] << std::endl;
        //注册拾取点函数
        this->Interactor->GetPicker()->Pick(
            this->Interactor->GetEventPosition()[0],
            this->Interactor->GetEventPosition()[1],
            0,  // always zero.
            sRender
//            this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()
            );
        //打印拾取点空间位置
        double picked[3];
        this->Interactor->GetPicker()->GetPickPosition(picked);
        std::cout << "Picked value: " << picked[0] << " " << picked[1] << " " << picked[2] << std::endl;
        //对拾取点进行标记
        vtkSmartPointer<vtkSphereSource> sphereSource =
            vtkSmartPointer<vtkSphereSource>::New();
        sphereSource->Update();

        vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
        mapper->SetInputConnection(sphereSource->GetOutputPort());

        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(picked);
        actor->SetScale(0.1);
        actor->GetProperty()->SetColor(0.0, 1.0, 0.0);
        sRender->AddActor(actor);
//        this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);

        vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
    }
};
/**************************************************************************************************/

vtkStandardNewMacro(PointPickerInteractorStyle);

int main(int, char *[])
{
    vtkSmartPointer<vtkSphereSource> sphereSource =
        vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetCenter(0.0, 0.0, 0.0);
    sphereSource->SetRadius(5.0);
    sphereSource->Update();

    double bounds[6];
    sphereSource->GetOutput()->GetBounds(bounds);
    std::cout << "sphere bounds:" << bounds[0] << "," << bounds[1] << "," << bounds[2] << "," << bounds[3]
              << "," << bounds[4] << "," << bounds[5]<< std::endl;

    // Define the cutting plane
    vtkSmartPointer<vtkPlane> plane =
        vtkSmartPointer<vtkPlane>::New();
    plane->SetOrigin(0, 0, 0);
    plane->SetNormal(0, 0, -1);

    // Need a plane collection for clipping
    vtkSmartPointer<vtkPlaneCollection>  planeCollection =
            vtkSmartPointer<vtkPlaneCollection>::New();
    planeCollection->AddItem(plane);

    // The clipper gennerates a clipped polygonial model
    vtkSmartPointer<vtkClipClosedSurface> clipper =
            vtkSmartPointer<vtkClipClosedSurface>::New();
    clipper->SetInputConnection(sphereSource->GetOutputPort());
    clipper->SetClippingPlanes(planeCollection);
//    clipper->SetTolerance(0.01);
    clipper->SetGenerateFaces(1);
    clipper->SetScalarModeToLabels();
    clipper->Update();


    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(sphereSource->GetOutputPort());

    vtkSmartPointer<vtkActor> actor =
        vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    vtkSmartPointer<vtkPolyDataMapper> outMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    outMapper->SetInputConnection(clipper->GetOutputPort());

    vtkSmartPointer<vtkActor> outActor =
        vtkSmartPointer<vtkActor>::New();
    outActor->SetMapper(outMapper);

    vtkSmartPointer<vtkNamedColors> colors =
        vtkSmartPointer<vtkNamedColors>::New();

    vtkSmartPointer<vtkRenderer> renderer =
        vtkSmartPointer<vtkRenderer>::New();
    renderer->SetBackground(colors->GetColor3d("Slate_grey").GetData());
    renderer->AddActor(actor);
//    renderer->SetBackground(1, 1, 1);
    renderer->SetViewport(0, 0, 0.5, 1);

    vtkSmartPointer<vtkRenderer> outRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    outRenderer->SetBackground(colors->GetColor3d("Slate_blue").GetData());
    outRenderer->AddActor(outActor);
    outRenderer->SetViewport(0.5, 0, 1, 1);

    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->SetSize(600, 300);
    renderWindow->AddRenderer(renderer);
    renderWindow->AddRenderer(outRenderer);

    // picker
//    vtkSmartPointer<vtkPointPicker> pointPicker =
//        vtkSmartPointer<vtkPointPicker>::New();
    vtkSmartPointer<vtkWorldPointPicker> pointPicker =
        vtkSmartPointer<vtkWorldPointPicker>::New();

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetPicker(pointPicker);
    renderWindowInteractor->SetRenderWindow(renderWindow);


//    vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
//        vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
    sRender = outRenderer;  // interactive
    vtkSmartPointer<PointPickerInteractorStyle> style =
        vtkSmartPointer<PointPickerInteractorStyle>::New();
    renderWindowInteractor->SetInteractorStyle(style);

    renderWindow->Render();
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}
